/**
 * 
 */
package ua.lviv.franko.solvers.oneDimention;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

import ua.lviv.franko.integration.ConstantFunction1D;
import ua.lviv.franko.matrix.RowType;
import ua.lviv.franko.matrix.hash.lu.HashMatrixLUStyle;
import ua.lviv.franko.matrix.hash.lu.LUFactorization;
import ua.lviv.franko.matrix.hash.lu.MatrixLUStyle;
import ua.lviv.franko.mlsFunctions.oneDimension.weightFunctions.CubicSpline;
import ua.lviv.franko.solvers.ElementMatrix;
import ua.lviv.franko.solvers.IElement1D;
import ua.lviv.franko.visualisation.NewOkCancelDialog;

/**
 * @author marko
 * 
 */
public class Solver {

	protected ArrayList<IElement1D>	elementsList;
	protected HashMatrixLUStyle		mainMatrix;
	protected double[]				b;

	protected BoundaryConditions	bc;

	public Solver(ArrayList<IElement1D> elementsList, BoundaryConditions bc) {
		this.bc = bc;
		this.elementsList = elementsList;
	}

	public void generate() {
		int N = elementsList.get(elementsList.size() - 1).lastNumber() + 1;
		mainMatrix = new HashMatrixLUStyle(RowType.ARRAY_TYPE, N);
		b = new double[N];

		for (Iterator<IElement1D> iterator = elementsList.iterator(); iterator.hasNext();) {
			IElement1D element = iterator.next();
			element.generateAll();
			ElementMatrix data = element.getAll();
			List<Integer> pos = data.getNodeList();
			for (int i = 0; i < pos.size(); i++) {
				for (int j = 0; j < pos.size(); j++) {
					mainMatrix.setValue(pos.get(j), pos.get(i), mainMatrix.getValue(pos.get(j), pos.get(i)) + data.matrix[j][i]);
				}
				b[pos.get(i)] += data.vector[i];
			}
		}
	}

	public double[] solve() {
//		MatrixLUStyle.printMatrix(mainMatrix);
//		System.out.println("============================");
//		MatrixLUStyle.printMatrix(b);
//		System.out.println("============================");
		bc.Apply(mainMatrix, b);
		LUFactorization lu = new LUFactorization(this.mainMatrix);
		return lu.calculate(b);
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		EquationParameters eqP = new EquationParameters(new ConstantFunction1D(1.0), new ConstantFunction1D(100.0), new ConstantFunction1D(0.0), new ConstantFunction1D(10.0));
		double a = 0.0;
		double b = 1.0;
		int n = 15;
		double h = (b - a) / (double) n;
		int NNN = 5;
		ArrayList<IElement1D> elements = new ArrayList<IElement1D>();
		int i = 0;
		int modifiedElements = 1;
		for (i = 0; i < n - modifiedElements; i++) {
			elements.add(new LinearElement(eqP, a + i * h, a + (i + 1) * h, i));

		}
		for (i = n - modifiedElements; i < n; i++) {
			// elements.add(new LinearElement(eqP, a + i * h, a + (i + 1) * h, i));
			elements.add(new EnrichedLinearElement(eqP, a + i * h, a + (i + 1) * h, elements.size() > 0 ? elements.get(elements.size() - 1).lastNumber() : 0, 1, NNN,
					new CubicSpline(), 1.01));
			// elements.add(new PreCalculatedEnrichedLinearElement(eqP, elements.size() > 0 ? elements.get(elements.size() - 1).lastNumber() : 0, a + i * h, a + (i + 1) * h));
			// elements.add(new EnrichedLinearElementWithFEM(eqP, a + i * h, a + (i + 1) * h, elements.size() > 0 ? elements.get(elements.size() - 1).lastNumber() : 0, NNN));
		}

		BoundaryConditions bc = new BoundaryConditions(true, 0.0, true, 0.0);
		Solver s = new Solver(elements, bc);
		s.generate();
		double[] res = s.solve();
//		for (int j = 0; j < res.length; j++) {
//			System.out.println(res[j]);
//		}

		XYSeries s2 = new XYSeries("result", true, true);

		NNN = 50;
		IElement1D el = null;
		System.out.println("myplot([");
		for (int j = 0; j < elements.size(); j++) {
			el = elements.get(j);
			double hhh = h / NNN;
			for (int k = 0; k < NNN; k++) {
				double x = a + h * j + k * hhh;
				double y = el.calculate(x, res);
				System.out.println(x + ", " + y);
				s2.add(x, y);
			}
		}
		s2.add(b, el.calculate(b, res));
		System.out.println(b + ", " + el.calculate(b, res));
		System.out.println("])");

		// for (int j = 0; j < res.length; j++) {
		// s2.add(a+j*h, res[j]);
		// }

		XYSeriesCollection col = new XYSeriesCollection();
		col.addSeries(s2);
		NewOkCancelDialog d = new NewOkCancelDialog(null, false, col);
		d.setLocationRelativeTo(null);
		d.setVisible(true);

	}
}
